home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- keywords: DOS, floppy
- subject: v11i083: Fast mtools, + mkdfs for SparcStation1 or Sun-3/80 Part 3
- from: viktor@melon.princeton.edu (Viktor Dukhovni)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 11, Issue 83
- Submitted-by: viktor@melon.princeton.edu (Viktor Dukhovni)
- Archive-name: sparc-mtools/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 3)."
- # Contents: mwrite.c
- # Wrapped by viktor@cucumber on Fri Mar 16 20:50:09 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'mwrite.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mwrite.c'\"
- else
- echo shar: Extracting \"'mwrite.c'\" \(10688 characters\)
- sed "s/^X//" >'mwrite.c' <<'END_OF_FILE'
- X/*
- X * Write (copy) a Unix file to MSDOS
- X *
- X * Emmet P. Gray US Army, HQ III Corps & Fort Hood
- X * ...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
- X * Directorate of Engineering & Housing
- X * Environmental Management Office
- X * Fort Hood, TX 76544-5057
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "msdos.h"
- X
- Xint fd; /* the file descriptor for the floppy */
- Xint dir_start; /* starting sector for directory */
- Xint dir_len; /* length of directory (in sectors) */
- Xint dir_entries; /* number of directory entries */
- Xint dir_chain[25]; /* chain of sectors in directory */
- Xint clus_size; /* cluster size (in sectors) */
- Xunsigned long clus_len; /* The cluster lenght in bytes */
- Xint fat_len; /* length of FAT table (in sectors) */
- Xint num_clus; /* number of available clusters */
- Xunsigned char *fatbuf; /* the File Allocation Table */
- Xchar *mcwd; /* the Current Working Directory */
- Xstatic char *inbuf; /* The input buffer */
- Xstatic char *outbuf; /* The output buffer */
- Xint bufsiz; /* Buffer size */
- Xint maxcontig; /* Max contiguous clusters per write call */
- Xlong size; /* Size of DOS file */
- X
- Xint full = 0;
- Xint textmode = 0;
- Xint nowarn = 0;
- Xint need_nl = 0;
- X
- Xextern union bootblock bb;
- Xvoid exit(), zapit(), writefat(), writedir(), free(), perror(), move();
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X extern int optind;
- X extern char *optarg;
- X int i, entry, ismatch, nogo, slot, start, dot, single;
- X int root, c, oops, verbose, first, mod_time;
- X char *filename, *newfile, tname[9], text[4], *fixname(), *getname();
- X char *unixname(), ans[10], *strncpy(), *pathname, *getpath(), *fixed;
- X char tmp[MAX_PATH], *target, *strcat(), *strcpy();
- X struct directory *dir, *search(), *writeit();
- X
- X if (init(2)) {
- X fprintf(stderr, "mwrite: Cannot initialize diskette\n");
- X exit(1);
- X }
- X /* get command line options */
- X oops = 0;
- X verbose = 0;
- X mod_time = 0;
- X while ((c = getopt(argc, argv, "tnvm")) != EOF) {
- X switch(c) {
- X case 't':
- X textmode = 1;
- X break;
- X case 'n':
- X nowarn = 1;
- X break;
- X case 'v':
- X verbose = 1;
- X break;
- X case 'm':
- X mod_time = 1;
- X break;
- X default:
- X oops = 1;
- X break;
- X }
- X }
- X
- X if (oops || (argc - optind) < 2) {
- X fprintf(stderr, "Usage: mwrite [-tnv] unixfile msdosfile\n");
- X fprintf(stderr, " or mwrite [-tnv] unixfile [unixfiles...] msdosdirectory\n");
- X exit(1);
- X }
- X root = 0;
- X if (!strcmp(argv[argc-1], "/") || !strcmp(argv[argc-1], "\\"))
- X root = 1;
- X
- X filename = getname(argv[argc-1]);
- X pathname = getpath(argv[argc-1]);
- X /* test if path is ok first */
- X if (subdir(pathname))
- X exit(1);
- X /* test if last argv is a dir */
- X if (isdir(filename) || root) {
- X if (!strlen(pathname)) {
- X /* don't alter the presence or */
- X /* absence of a leading separator */
- X strcpy(tmp, filename);
- X }
- X else {
- X strcpy(tmp, pathname);
- X strcat(tmp, "/");
- X strcat(tmp, filename);
- X }
- X /* subdir is not recursive */
- X subdir(tmp);
- X single = 0;
- X }
- X else {
- X single = 1;
- X /* too many arguments */
- X if ((argc - optind) != 2) {
- X fprintf(stderr, "mwrite: too many arguments or destination directory omitted\n");
- X exit(1);
- X }
- X }
- X
- X
- X clus_len = clus_size * MSECSIZ;
- X /* Round cylinder up to nearest cluster multiple */
- X bufsiz = NTRACK(bb.sb) * NSECT(bb.sb);
- X maxcontig = (bufsiz += clus_size - (--bufsiz) % clus_size) / clus_size;
- X bufsiz *= MSECSIZ;
- X
- X if( (outbuf = (char *)malloc(bufsiz)) == NULL ||
- X ( inbuf = (char *)malloc(bufsiz)) == NULL) {
- X fprintf(stderr,
- X "mwrite: Cannot allocate I/O buffers\n");
- X perror("malloc") ;
- X exit(1);
- X }
- X
- X for (i=optind; i<argc-1; i++) {
- X if (single)
- X fixed = fixname(argv[argc-1], verbose);
- X else
- X fixed = fixname(argv[i], verbose);
- X
- X strncpy(tname, fixed, 8);
- X strncpy(text, fixed+8, 3);
- X tname[8] = '\0';
- X text[3] = '\0';
- X
- X target = unixname(tname, text);
- X /* see if exists and get slot */
- X ismatch = 0;
- X slot = -1;
- X dot = 0;
- X nogo = 0;
- X first = 1;
- X for (entry=0; entry<dir_entries; entry++) {
- X dir = search(entry);
- X /* save the '.' entry info */
- X if (first) {
- X first = 0;
- X if ((dir->attr & 0x10) && dir->name[0] == '.') {
- X dot = dir->start[1]*0x100 + dir->start[0];
- X continue;
- X }
- X }
- X /* is empty */
- X if (dir->name[0] == 0x0) {
- X if (slot < 0)
- X slot = entry;
- X break;
- X }
- X /* is erased */
- X if (dir->name[0] == 0xe5) {
- X if (slot < 0)
- X slot = entry;
- X continue;
- X }
- X /* is dir or volume lable */
- X if ((dir->attr & 0x10) || (dir->attr & 0x08))
- X continue;
- X
- X strncpy(tname, (char *) dir->name, 8);
- X strncpy(text, (char *) dir->ext, 3);
- X tname[8] = '\0';
- X text[3] = '\0';
- X
- X newfile = unixname(tname, text);
- X /* if file exists, delete it first */
- X if (!strcmp(target, newfile)) {
- X ismatch = 1;
- X start = dir->start[1]*0x100 + dir->start[0];
- X if (nowarn) {
- X zapit(start);
- X dir->name[0] = 0xe5;
- X writedir(entry, dir);
- X if (slot < 0)
- X slot = entry;
- X } else {
- X while (1) {
- X printf("File \"%s\" exists, overwrite (y/n) ? ", target);
- X gets(ans);
- X if (ans[0] == 'n' || ans[0] == 'N') {
- X nogo = 1;
- X break;
- X }
- X if (ans[0] == 'y' || ans[0] == 'Y') {
- X zapit(start);
- X dir->name[0] = 0xe5;
- X writedir(entry, dir);
- X if (slot < 0)
- X slot = entry;
- X break;
- X }
- X }
- X }
- X }
- X free(newfile);
- X if (ismatch)
- X break;
- X }
- X if (nogo) { /* chickened out... */
- X free(fixed);
- X free(target);
- X continue;
- X }
- X /* no '.' entry means root directory */
- X if (dot == 0 && slot < 0) {
- X fprintf(stderr, "mwrite: No directory slots\n");
- X exit(1);
- X }
- X /* make the directory grow */
- X if (dot && slot < 0) {
- X if (grow(dot)) {
- X fprintf(stderr, "mwrite: Disk full\n");
- X exit(1);
- X }
- X /* first entry in 'new' directory */
- X slot = entry;
- X }
- X if (!single)
- X printf("Copying %s\n", target);
- X /* write the file */
- X if (dir = writeit(fixed, argv[i], verbose, mod_time))
- X writedir(slot, dir);
- X
- X free(fixed);
- X free(target);
- X
- X if (full) {
- X fprintf(stderr, "mwrite: Disk Full\n");
- X break;
- X }
- X if (single)
- X break;
- X }
- X /* write FAT sectors */
- X writefat();
- X close(fd);
- X exit(0);
- X}
- X
- X/*
- X * Open the named file for write, create the cluster chain, return the
- X * directory structure or NULL on error.
- X */
- X
- Xstruct directory *
- Xwriteit(fixed, path, verbose, mod_time)
- Xchar *fixed, *path;
- Xint verbose, mod_time;
- X{
- X FILE *fp;
- X int fat, firstfat, oldfat, curfat, chain;
- X long time(), now;
- X struct directory *dir, *mk_entry();
- X struct stat stbuf;
- X
- X if (stat(path, &stbuf) < 0) {
- X fprintf(stderr, "mwrite: Can't stat \"%s\"\n", path);
- X return(NULL);
- X }
- X
- X if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
- X if (verbose)
- X fprintf(stderr, "mwrite: \"%s\" is a directory\n", path);
- X return(NULL);
- X }
- X
- X if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
- X fprintf(stderr, "mwrite: \"%s\" is not a regular file\n", path);
- X return(NULL);
- X }
- X /* preserve mod time? */
- X if (mod_time)
- X now = stbuf.st_mtime;
- X else
- X time(&now);
- X
- X if (!(fp = fopen(path, "r"))) {
- X fprintf(stderr, "mwrite: Can't open \"%s\" for read\n", path);
- X return(NULL);
- X }
- X#ifdef HAVE_SETBUFFER
- X setbuffer(fp,inbuf,bufsiz) ;
- X#endif
- X
- X fat = oldfat = firstfat = nextfat(size=0);
- X for(;;) {
- X if (fat == -1) {
- X full = 1;
- X if(size)
- X zapit(firstfat) ;
- X return(NULL) ;
- X }
- X
- X /*
- X * grab a bunch of contiguous FAT slots
- X * curfat -> 1 + last grabbed slot.
- X * FIX ME!
- X * someone should try to read and cache a cylinder on
- X * first write access, do write to memory until a new
- X * cylinder is requested.
- X * The overhead is higher, but should be more robust under
- X * fragmentation.
- X * In mread this may even be a win! (Also see comments
- X * in putclusters() )
- X */
- X for(curfat=fat;
- X ++curfat < fat + maxcontig &&
- X nextfat(curfat-1) == curfat;) ;
- X
- X if((oldfat=putclusters(oldfat,fat, curfat, fp)) == 0)
- X break ;
- X
- X fat = nextfat(oldfat);
- X }
- X fclose(fp);
- X dir = mk_entry(fixed, 0x20, firstfat, size, now);
- X return(dir);
- X}
- X
- X/*
- X * Write to the cluster chain from the named Unix file descriptor.
- X * N.B. all the clusters in the chain are contiguous.
- X */
- X
- X
- Xstatic int writepos = -1;
- X
- Xint
- Xputclusters(chain,start,end,fp)
- XFILE *fp;
- X{
- X static int blk;
- X int c, nclust, current, eof=0;
- X int buflen = ( end - start ) * MSECSIZ ;
- X register char *tbuf=outbuf;
- X
- X blk = (start - 2)*clus_size + dir_start + dir_len;
- X
- X if (textmode) { /* '\n' to '\r\n' translation */
- X current = 0;
- X if (need_nl) {
- X tbuf[current++] = '\n';
- X need_nl = 0;
- X }
- X while (current < buflen) {
- X if ((c = fgetc(fp)) == EOF) {
- X /* put a file EOF marker */
- X tbuf[current++] = 0x1a;
- X ++eof;
- X break;
- X }
- X if (c == '\n') {
- X tbuf[current++] = '\r';
- X /* if at the end of the buffer */
- X if (current == buflen) {
- X need_nl++;
- X break;
- X }
- X }
- X tbuf[current++] = c;
- X }
- X }
- X else {
- X /*
- X * FIX ME!
- X * The kernel guarantees to satisfy REGULAR file
- X * read requests unless EOF,
- X * This code will break on pipes, sockets, etc.
- X * To fix one should do something akin to the
- X * "atomic" I/O of Berkeley multiprocess dump, which loops
- X * on read/write requests until EOF or enough data has been
- X * gathered. If you want to do this please change
- X * all instances of read/write with Read/Write and
- X * add an offset parameter to allow arbitrary sorting/queuing
- X * etc, behind the back of the DOS code. This will
- X * make the overall code much cleaner, and we
- X * can put Read/Write in a sysdep.c where they belong.
- X * Also one may want to memory map the input file. Avoiding
- X * redundant copying to user space, this is for perfectionists
- X * as the floppy is much slower than UNIX disks, so gains
- X * here are small.
- X */
- X if ( (current = fread(outbuf, 1, buflen, fp)) < 0) {
- X perror("putcluster: fread");
- X exit(1);
- X }
- X if ( current != buflen )
- X ++eof;
- X }
- X
- X size += current;
- X
- X if (current == 0) {
- X putfat(chain,0xfff) ;
- X return(0) ;
- X }
- X
- X putfat(chain,start) ;
- X
- X /*
- X * chain the clusters, we are about to overwrite
- X * making sure to terminate the chain.
- X */
- X for(end=start; current > clus_len ; ++end) {
- X putfat(end,end+1);
- X current -= clus_len ;
- X }
- X putfat(end, 0xfff) ;
- X
- X if ( blk != writepos )
- X move(blk);
- X
- X nclust=(end-start)+1;
- X writepos = eof ? -1 : blk + nclust*clus_size;
- X buflen = nclust * clus_size * MSECSIZ;
- X
- X if (write(fd, outbuf, buflen) != buflen) {
- X perror("putclusters: write");
- X exit(1);
- X }
- X
- X return(eof ? 0: end) ;
- X}
- X
- X/*
- X * Returns next free cluster or -1 if none are available.
- X */
- X
- Xint
- Xnextfat(last)
- Xint last;
- X{
- X register int i;
- X
- X for (i=last+1; i<num_clus+2; i++) {
- X if (!getfat(i))
- X return(i);
- X }
- X return(-1);
- X
- X}
- END_OF_FILE
- if test 10688 -ne `wc -c <'mwrite.c'`; then
- echo shar: \"'mwrite.c'\" unpacked with wrong size!
- fi
- # end of 'mwrite.c'
- fi
- echo shar: End of archive 3 \(of 3\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- Viktor Dukhovni <viktor@math.princeton.edu> : ARPA
- <...!uunet!princeton!math!viktor> : UUCP
- Fine Hall, Washington Rd., Princeton, NJ 08544 : US-Post
- +1-(609)-258-5792 : VOICE
-
-